package com.zhiche.wms.configuration;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.InterfaceEventEnum;
import com.zhiche.wms.core.supports.enums.NodeOptionEnum;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.domain.model.base.StorehouseNode;
import com.zhiche.wms.domain.model.inbound.InboundInspectLine;
import com.zhiche.wms.domain.model.inbound.InboundNoticeHeader;
import com.zhiche.wms.domain.model.inbound.InboundNoticeLine;
import com.zhiche.wms.domain.model.opbaas.StatusLog;
import com.zhiche.wms.domain.model.otm.OtmOrderRelease;
import com.zhiche.wms.domain.model.otm.OtmShipment;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeHeader;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeLine;
import com.zhiche.wms.domain.model.outbound.OutboundPrepareLine;
import com.zhiche.wms.domain.model.outbound.OutboundShipHeader;
import com.zhiche.wms.service.common.IntegrationService;
import com.zhiche.wms.service.constant.PutAwayType;
import com.zhiche.wms.service.constant.SourceSystem;
import com.zhiche.wms.service.dto.OTMEvent;
import com.zhiche.wms.service.inbound.IInboundInspectLineService;
import com.zhiche.wms.service.inbound.IInboundNoticeHeaderService;
import com.zhiche.wms.service.inbound.IInboundNoticeLineService;
import com.zhiche.wms.service.inbound.IInboundPutawayHeaderService;
import com.zhiche.wms.service.opbaas.IOrderReleaseService;
import com.zhiche.wms.service.opbaas.IStatusLogService;
import com.zhiche.wms.service.otm.IOtmShipmentService;
import com.zhiche.wms.service.outbound.IOutboundNoticeHeaderService;
import com.zhiche.wms.service.outbound.IOutboundNoticeLineService;
import com.zhiche.wms.service.outbound.IOutboundPrepareLineService;
import com.zhiche.wms.service.outbound.IOutboundShipLineService;
import com.zhiche.wms.service.sys.IStorehouseNodeService;
import com.zhiche.wms.service.utils.BusinessNodeExport;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * lisa-仓库节点切面增强
 */
@Aspect
@Component
public class StoreHouseAopHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private IInboundInspectLineService inspectLineService;
    @Autowired
    private IInboundNoticeLineService noticeLineService;
    @Autowired
    private IInboundNoticeHeaderService noticeHeaderService;
    @Autowired
    private IOutboundNoticeLineService outboundNoticeLineService;
    @Autowired
    private IOutboundNoticeHeaderService outboundNoticeHeaderService;
    @Autowired
    private IOutboundShipLineService outboundShipLineService;
    @Autowired
    private IOrderReleaseService orderReleaseService;
    @Autowired
    private IInboundPutawayHeaderService inboundPutawayHeaderService;
    @Autowired
    private IStorehouseNodeService storehouseNodeService;
    @Autowired
    private IOtmShipmentService shipmentService;
    @Autowired
    private IStatusLogService statusLogService;
    @Autowired
    private IntegrationService integrationService;
    @Autowired
    private BusinessNodeExport nodeExport;
    @Autowired
    private IOutboundPrepareLineService prepareLineService;

    /**
     * 切入点--入库确认前入库质检
     */
    @Pointcut("execution(public * com.zhiche.wms.service.inbound.IInboundPutawayHeaderService.updateByNoticeLineId(..))")
    public void inboundOption() {

    }

    /**
     * “入库通知单生成后是否自动入库”的切入点
     */
    @Pointcut("execution(public * com.zhiche.wms.service.inbound.IInboundNoticeHeaderService.insertInboundNotice(..))")
    public void inboundNoticeOption() {

    }

    /**
     * “出库通知单生成后是否自动出库”的切入点
     */
    @Pointcut("execution(public * com.zhiche.wms.service.outbound.IOutboundNoticeHeaderService.insertOutboundNotice(..))")
    public void outboundNoticeOption() {

    }

    /**
     * 出库前是否必须备料的切入点
     */
    @Pointcut("execution(public * com.zhiche.wms.service.outbound.IOutboundShipLineService.shipByNoticeLineId(..))")
    public void outboundOption() {

    }


    /**
     * 前置增强
     */
    @Before("inboundOption()")
    public void doBefore(JoinPoint joinPoint) {
        //方法名
        String method = joinPoint.getSignature().getName();
        if (logger.isInfoEnabled()) {
            logger.info("IInboundPutawayHeaderService.updateByNoticeLineId AOP-->:{}", method);
        }
        //参数
        Object[] args = joinPoint.getArgs();
        //通知单获取仓库
        Object arg = args[0];
        if (arg instanceof Long) {
            Long noticeLineId = (Long) arg;
            InboundNoticeLine noticeLine = noticeLineService.selectById(noticeLineId);
            if (noticeLine == null) {
                throw new BaseException("未查询到入库通知单信息");
            }
            InboundNoticeHeader noticeHeader = noticeHeaderService.selectById(noticeLine.getHeaderId());
            //判断仓库关联节点
            EntityWrapper<StorehouseNode> snEW = new EntityWrapper<>();
            snEW.eq("store_house_id", noticeHeader.getStoreHouseId())
                    .eq("node_id", NodeOptionEnum.NODE_INBOUND_INSPECT.getId())
                    .eq("status", TableStatusEnum.STATUS_1.getCode());
            int count = storehouseNodeService.selectCount(snEW);
            if (count > 0) {
                //必须入库质检  状态非质检完成
                EntityWrapper<InboundInspectLine> ew = new EntityWrapper<>();
                ew.eq("notice_line_id", arg)
                        .orderBy("id", false);
                InboundInspectLine inboundInspectLine = inspectLineService.selectOne(ew);
                if (inboundInspectLine == null) {
                    throw new BaseException("未查询到LineId " + arg + "质检信息");
                }
                if (TableStatusEnum.STATUS_0.getCode().equals(inboundInspectLine.getStatus())) {
                    throw new BaseException("查询到LineId " + arg + "未质检完成");
                }
            }
        }

    }


    /**
     * 后置增强（如果是自动入库，则入库通知单生成后自动入库）
     */
    @After("inboundNoticeOption()")
    public void insertInboundAfter(JoinPoint joinPoint) {
        //方法名
        String method = joinPoint.getSignature().getName();
        if (logger.isInfoEnabled()) {
            logger.info("IInboundNoticeHeaderService.insertInboundNotice AOP-->:{}", method);
        }
        //参数
        Object[] args = joinPoint.getArgs();
        if (args[0] instanceof InboundNoticeHeader) {
            InboundNoticeHeader noticeHeader = (InboundNoticeHeader) args[0];
            List<InboundNoticeLine> lineList = noticeHeader.getInboundNoticeLineList();
            //判断仓库关联节点
            EntityWrapper<StorehouseNode> snEW = new EntityWrapper<>();
            snEW.eq("store_house_id", noticeHeader.getStoreHouseId())
                    .eq("node_id", NodeOptionEnum.NODE_INBOUND_AUTO.getId())
                    .eq("status", TableStatusEnum.STATUS_1.getCode());
            int count = storehouseNodeService.selectCount(snEW);
            if (count > 0) {
                //自动入库
                if (CollectionUtils.isNotEmpty(lineList)) {
                    for (InboundNoticeLine line : lineList) {
                        inboundPutawayHeaderService.updateByNoticeLineId(line.getId(), PutAwayType.NOTICE_PUTAWAY,
                                SourceSystem.AUTO);
                    }
                }
            }
        }
    }


    /**
     * 后置增强（如果是自动出库，则出库通知单生成后自动出库）
     */
    @After("outboundNoticeOption()")
    public void insertoutboundAfter(JoinPoint joinPoint) {
        //方法名
        String method = joinPoint.getSignature().getName();
        if (logger.isInfoEnabled()) {
            logger.info("IOutboundNoticeHeaderService.insertOutboundNotice AOP-->:{}", method);
        }
        //参数
        Object[] args = joinPoint.getArgs();
        Object arg = args[0];
        if (arg instanceof OutboundNoticeHeader) {
            OutboundNoticeHeader noticeHeader = (OutboundNoticeHeader) arg;
            List<OutboundNoticeLine> lineList = noticeHeader.getOutboundNoticeLineList();
            //判断仓库关联节点
            EntityWrapper<StorehouseNode> snEW = new EntityWrapper<>();
            snEW.eq("store_house_id", noticeHeader.getStoreHouseId())
                    .eq("node_id", NodeOptionEnum.NODE_OUTBOUND_AUTO.getId())
                    .eq("status", TableStatusEnum.STATUS_1.getCode());
            int count = storehouseNodeService.selectCount(snEW);
            if (count > 0) {
                //自动出库
                if (CollectionUtils.isNotEmpty(lineList)) {
                    for (OutboundNoticeLine line : lineList) {
                        outboundShipLineService.shipByNoticeLineId(line.getId(), PutAwayType.NOTICE_PUTAWAY, SourceSystem.AUTO);
                    }
                }
            }
        }
    }


    @Before("outboundOption()")
    public void outboundBefore(JoinPoint joinPoint) {
        //方法名
        String method = joinPoint.getSignature().getName();
        //参数
        Object[] args = joinPoint.getArgs();
        if (logger.isInfoEnabled()) {
            logger.info("IOutboundShipHeaderService.shipByNoticeLineId AOP-->:{}", method);
        }
        //通知单获取仓库
        Object arg = args[0];
        if (arg instanceof Long) {
            Long noticeLineId = (Long) arg;
            OutboundNoticeLine noticeLine = outboundNoticeLineService.selectById(noticeLineId);
            if (noticeLine == null) {
                throw new BaseException("未查询到入库通知单信息");
            }
            OutboundNoticeHeader noticeHeader = outboundNoticeHeaderService.selectById(noticeLine.getHeaderId());
            //判断仓库关联节点
            EntityWrapper<StorehouseNode> snEW = new EntityWrapper<>();
            snEW.eq("store_house_id", noticeHeader.getStoreHouseId())
                    .eq("node_id", NodeOptionEnum.NODE_OUTBOUND_PREPARE.getId())
                    .eq("status", TableStatusEnum.STATUS_1.getCode());
            int count = storehouseNodeService.selectCount(snEW);
            if (count > 0) {
                //必须备料
                EntityWrapper<OutboundPrepareLine> ew = new EntityWrapper<>();
                ew.eq("notice_line_id", args[0]);
                int hasPre = prepareLineService.selectCount(ew);
                if (hasPre < 1) {
                    throw new BaseException("通知单lineId " + args[0] + "还未备料");
                }
            }
        }
    }

    /**
     * 出库后是否自动装车发运
     */
    @AfterReturning(pointcut = "outboundOption()", returning = "returnValue")
    public void outboundAfter(JoinPoint joinPoint, OutboundShipHeader returnValue) {
        String method = joinPoint.getSignature().getName();
        if (logger.isInfoEnabled()) {
            logger.info("IOutboundShipHeaderService.shipByNoticeLineId AOP-->:{}", method);
        }
        //判断仓库关联节点
        EntityWrapper<StorehouseNode> snEW = new EntityWrapper<>();
        snEW.eq("store_house_id", returnValue.getStoreHouseId())
                .eq("node_id", NodeOptionEnum.NODE_OUTBOUND_TRUCK.getId())
                .eq("status", TableStatusEnum.STATUS_1.getCode());
        int count = storehouseNodeService.selectCount(snEW);
        if (count > 0) {
            //自动装车发运
            Object arg = joinPoint.getArgs()[0];
            if (arg instanceof Long) {
                //通知单明细  -- line source_key 发运
                autoShip((Long) arg);
            }
        }
    }

    private void autoShip(Long arg) {
        OutboundNoticeLine noticeLine = outboundNoticeLineService.selectById(arg);
        if (StringUtils.isNotBlank(noticeLine.getLineSourceKey())) {
            EntityWrapper<OtmOrderRelease> orEW = new EntityWrapper<>();
            orEW.eq("release_gid", noticeLine.getLineSourceKey())
                    .ne("status", TableStatusEnum.STATUS_50.getCode())
                    .orderBy("gmt_create", false)
                    .orderBy("id", false);
            OtmOrderRelease orderRelease = orderReleaseService.selectOne(orEW);
            OtmOrderRelease release = new OtmOrderRelease();
            release.setId(orderRelease.getId());
            release.setStatus(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
            orderRelease.setGmtModified(null);
            orderReleaseService.updateById(release);
            //回传运单发运到OTM
            sendOtm(release);
            //记录状态日志
            saveStatusLog(release);
            //统计指令下是否都发运
            EntityWrapper<OtmOrderRelease> allShipEW = new EntityWrapper<>();
            allShipEW.eq("shipment_gid", orderRelease.getShipmentGid())
                    .ne("status", TableStatusEnum.STATUS_50.getCode());
            int allShipCount = orderReleaseService.selectCount(allShipEW);
            EntityWrapper<OtmOrderRelease> shipEW = new EntityWrapper<>();
            shipEW.eq("shipment_gid", orderRelease.getShipmentGid())
                    .eq("status", TableStatusEnum.STATUS_BS_DISPATCH.getCode());
            int shipCount = orderReleaseService.selectCount(shipEW);
            if (shipCount == allShipCount) {
                //如果指令下运单都发运
                EntityWrapper<OtmShipment> shipmentEW = new EntityWrapper<>();
                shipmentEW.eq("shipment_gid", orderRelease.getShipmentGid())
                        .ne("status", TableStatusEnum.STATUS_50.getCode())
                        .orderBy("gmt_create", false)
                        .orderBy("id", false);
                OtmShipment otmShipment = shipmentService.selectOne(shipmentEW);
                OtmShipment shipment = new OtmShipment();
                shipment.setId(otmShipment.getId());
                shipment.setStatus(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
                shipmentService.updateById(shipment);
                new Thread(() -> {
                    StatusLog sl = new StatusLog();
                    sl.setTableType(TableStatusEnum.STATUS_20.getCode());
                    sl.setTableId(String.valueOf(otmShipment.getId()));
                    sl.setStatus(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
                    sl.setStatusName(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
                    sl.setUserCreate("系统自动发运");
                    statusLogService.insert(sl);
                }).start();
            }
        }
    }

    private void saveStatusLog(OtmOrderRelease release) {
        new Thread(() -> {
            StatusLog sl = new StatusLog();
            sl.setTableType(TableStatusEnum.STATUS_10.getCode());
            sl.setTableId(String.valueOf(release.getId()));
            sl.setStatus(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
            sl.setStatusName(TableStatusEnum.STATUS_BS_DISPATCH.getCode());
            sl.setUserCreate("系统自动发运");
            statusLogService.insert(sl);
        }).start();
    }

    private void sendOtm(OtmOrderRelease release) {
        new Thread(() -> {
            OTMEvent otmEvent = integrationService.getOtmEvent(String.valueOf(release.getId()),
                    release.getReleaseGid(),
                    InterfaceEventEnum.BS_OP_DELIVERY.getCode(),
                    release.getShipmentGid(),
                    "已发运回传OTM");
            String res = nodeExport.exportEventToOTM(otmEvent);
            integrationService.insertExportLog(String.valueOf(release.getId()),
                    otmEvent,
                    res,
                    "已发运回传OTM",
                    InterfaceEventEnum.BS_OP_DELIVERY.getCode());
        }).start();
    }
}
